
#include "gkt_board.h"
#include "gkt_debug.h"
#include "gkt_os.h"
#include "gkt_gpio.h"
#include "gkt_wakeup.h"
#include "gkt_sliding_closure.h"

#if GKT_SLIDING_CLOSURE_ENABLE \
	&& defined(GKT_CONFIG_SLIDING_CLOSURE_WKIO_PIN)	\
	&& defined(GKT_CONFIG_SLIDING_CLOSURE_GPIO_PIN)

#if (0 == GKT_CONFIG_SLIDING_CLOSURE_DETECT_LEVEL)
#define SLIDING_CLOSURE_WKIO_POLARITY	GKT_WKIO_POL_FALL_EDGE
#define SLIDING_CLOSURE_GPIO_FLAGS	\
	(GKT_GPIO_F_INPUT | GKT_GPIO_F_PULL_UP | GKT_GPIO_F_INT_EDGE_RAISE \
		| GKT_GPIO_F_INT_DEBOUNCE | GKT_GPIO_F_INT_MASKED)
#else
#define SLIDING_CLOSURE_WKIO_POLARITY	GKT_WKIO_POL_RAISE_EDGE
#define SLIDING_CLOSURE_GPIO_FLAGS	\
	(GKT_GPIO_F_INPUT | GKT_GPIO_F_PULL_DOWN | GKT_GPIO_F_INT_EDGE_FALL \
		| GKT_GPIO_F_INT_DEBOUNCE | GKT_GPIO_F_INT_MASKED)
#endif

typedef struct _sliding_closure {
	int detect;

#if GKT_SLIDING_CLOSURE_MAGNET_ENABLE
	gkt_mutex_t	magnet_mutex;
	gkt_soft_timer_t	magnet_timer_id;
	int	magnet_timer_start;
	int	magnet_magnetic;
	int	magnet_switch_status;
#endif

	gkt_sliding_closure_notify_fn	notify;
} sliding_closure_s;
static sliding_closure_s s_sliding_closure;

#if GKT_SLIDING_CLOSURE_MAGNET_ENABLE

enum {
	SLIDING_CLOSURE_MAGNET_SWITCH_NONE = 0,
	SLIDING_CLOSURE_MAGNET_SWITCH_DOING,
	SLIDING_CLOSURE_MAGNET_SWITCH_DONE,
	SLIDING_CLOSURE_MAGNET_SWITCH_MAX
};

#if defined(GKT_CONFIG_SLIDING_CLOSURE_MAGNET_SWITCH_TIME_MS) \
	&& (GKT_CONFIG_SLIDING_CLOSURE_MAGNET_SWITCH_TIME_MS > 0)
#define SLIDING_CLOSURE_MAGNET_SWITCH_TIME_MS	\
	GKT_CONFIG_SLIDING_CLOSURE_MAGNET_SWITCH_TIME_MS
#else
#define SLIDING_CLOSURE_MAGNET_SWITCH_TIME_MS	1000
#endif

static void sliding_closure_magnet_switch_timeout(void *arguments)
{
	int retval;

	gkt_info("sliding_closure_magnet_switch_timeout: (%d) start(%d), magnetic(%d)\n",
		s_sliding_closure.detect, s_sliding_closure.magnet_timer_start,
		s_sliding_closure.magnet_magnetic);

	gkt_mutex_lock(s_sliding_closure.magnet_mutex, GKT_INFINITE);
	if (s_sliding_closure.magnet_timer_start) {
		retval = gkt_gpio_set_pin_level(GKT_CONFIG_SLIDING_CLOSURE_MAGNET_GPIO_PIN,
						GKT_CONFIG_SLIDING_CLOSURE_MAGNET_LEVEL);
		if (GKT_SUCCESS == retval) {
			s_sliding_closure.magnet_magnetic = 1;
			s_sliding_closure.magnet_switch_status = SLIDING_CLOSURE_MAGNET_SWITCH_DONE;
			gkt_info("sliding_closure_magnet: degauss -> 1\n");
		}
	}
	s_sliding_closure.magnet_timer_start = 0;
	gkt_mutex_unlock(s_sliding_closure.magnet_mutex);
}

void gkt_sliding_closure_magnet_control(int magnetic)
{
	int retval;

	gkt_info("sliding_closure_magnet: (%d) req(%d), prev(%d)\n",
		s_sliding_closure.detect, magnetic, 
		s_sliding_closure.magnet_magnetic);

	gkt_mutex_lock(s_sliding_closure.magnet_mutex, GKT_INFINITE);
	if (s_sliding_closure.magnet_magnetic != magnetic) {
		if (magnetic) {
			if (s_sliding_closure.magnet_timer_start) {
				gkt_soft_timer_stop(s_sliding_closure.magnet_timer_id);
				s_sliding_closure.magnet_timer_start = 0;
			}

			retval = gkt_gpio_set_pin_level(GKT_CONFIG_SLIDING_CLOSURE_MAGNET_GPIO_PIN,
						GKT_CONFIG_SLIDING_CLOSURE_MAGNET_LEVEL);
			if (GKT_SUCCESS == retval)
				s_sliding_closure.magnet_magnetic = 1;
			s_sliding_closure.magnet_switch_status = SLIDING_CLOSURE_MAGNET_SWITCH_NONE;
		}
		else if (SLIDING_CLOSURE_MAGNET_SWITCH_NONE == s_sliding_closure.magnet_switch_status) {
			retval = gkt_gpio_set_pin_level(GKT_CONFIG_SLIDING_CLOSURE_MAGNET_GPIO_PIN,
							GKT_CONFIG_SLIDING_CLOSURE_MAGNET_LEVEL ? 0 : 1);
			if (GKT_SUCCESS == retval) {
				s_sliding_closure.magnet_magnetic = 0;
				s_sliding_closure.magnet_switch_status = SLIDING_CLOSURE_MAGNET_SWITCH_DOING;
				retval = gkt_soft_timer_start(s_sliding_closure.magnet_timer_id,
							SLIDING_CLOSURE_MAGNET_SWITCH_TIME_MS);
				if (GKT_SUCCESS == retval)
					s_sliding_closure.magnet_timer_start = 1;
			}
		}
	}
	gkt_mutex_unlock(s_sliding_closure.magnet_mutex);
}

void gkt_sliding_closure_magnet_degauss_sync(void)
{
	uint32_t counter = SLIDING_CLOSURE_MAGNET_SWITCH_TIME_MS / 10;

	do {
		if (s_sliding_closure.magnet_magnetic 
			|| !s_sliding_closure.magnet_timer_start)
		{
			break;
		}

		gkt_thread_sleep(10);
	} while (--counter > 0);
}
#endif

int gkt_sliding_closure_is_detected(void)
{
	uint32_t level;
	int retval;

	retval = gkt_gpio_get_pin_level(GKT_CONFIG_SLIDING_CLOSURE_GPIO_PIN,
				&level);
	return ((GKT_SUCCESS == retval) 
			&& (GKT_CONFIG_SLIDING_CLOSURE_DETECT_LEVEL == level)) ? 1 : 0;
}

static void sliding_closure_detect_notify(void)
{
	int detect;

	detect = gkt_sliding_closure_is_detected();
	gkt_trace("sliding_closure_detect: %d --> %d\n", 
		s_sliding_closure.detect, detect);

	if (detect && (detect != s_sliding_closure.detect)) {
		s_sliding_closure.detect = detect;
		if (s_sliding_closure.notify)
			(*s_sliding_closure.notify)(detect);
	}
}

static void sliding_closure_undetect_notify(uint32_t pin)
{
	int detect;

	gkt_unused(pin);

	detect = gkt_sliding_closure_is_detected();
	gkt_trace("sliding_closure_undetect: %d --> %d\n", 
		s_sliding_closure.detect, detect);

	if (!detect && (detect != s_sliding_closure.detect)) {
		s_sliding_closure.detect = detect;
		if (s_sliding_closure.notify)
			(*s_sliding_closure.notify)(detect);
	}
}

void gkt_sliding_closure_register_notify(
			gkt_sliding_closure_notify_fn notify)
{
	s_sliding_closure.notify = notify;
}

int gkt_sliding_closure_init(void)
{
	gkt_wkio_attr_s attr;
	int wakedup, retval;

	retval = gkt_gpio_config(GKT_CONFIG_SLIDING_CLOSURE_GPIO_PIN,
					SLIDING_CLOSURE_GPIO_FLAGS, 
					sliding_closure_undetect_notify);
	if (retval != GKT_SUCCESS) {
		gkt_error("sliding_closure: config gpio failed %d\n", retval);
		return retval;
	}
	s_sliding_closure.detect = gkt_sliding_closure_is_detected();
	gkt_gpio_interrupt_unmask(GKT_CONFIG_SLIDING_CLOSURE_GPIO_PIN);

	gkt_info("sliding_closure: detect(%d)\n", s_sliding_closure.detect);

#if GKT_SLIDING_CLOSURE_MAGNET_ENABLE
	s_sliding_closure.magnet_mutex = gkt_mutex_create(0);
	if (!s_sliding_closure.magnet_mutex)
		gkt_error("sliding_closure: create magnet mutex failed!\n");

	s_sliding_closure.magnet_timer_start = 0;
	s_sliding_closure.magnet_timer_id = 
		gkt_soft_timer_create(GKT_SOFT_TIMER_ONCE,
				sliding_closure_magnet_switch_timeout, NULL);
	if (!s_sliding_closure.magnet_timer_id)
		gkt_error("sliding_closure: create magnet timer failed!\n");

	s_sliding_closure.magnet_magnetic = 1;	/* default state */
	s_sliding_closure.magnet_switch_status = SLIDING_CLOSURE_MAGNET_SWITCH_NONE;
	retval = gkt_gpio_config(GKT_CONFIG_SLIDING_CLOSURE_MAGNET_GPIO_PIN,
				GKT_GPIO_F_OUTPUT, NULL);
	if (GKT_SUCCESS== retval) {
		gkt_gpio_set_pin_level(GKT_CONFIG_SLIDING_CLOSURE_MAGNET_GPIO_PIN,
				GKT_CONFIG_SLIDING_CLOSURE_MAGNET_LEVEL);
	}
	else
		gkt_error("sliding_closure: config magnet gpio failed %d\n", retval);

	gkt_info("sliding_closure: magnet_magnetic(%d)\n", s_sliding_closure.magnet_magnetic);
#endif

	attr.polarity = SLIDING_CLOSURE_WKIO_POLARITY;
	attr.check = gkt_sliding_closure_is_detected;
	attr.notify = sliding_closure_detect_notify;
	retval = gkt_wkio_set(GKT_CONFIG_SLIDING_CLOSURE_WKIO_PIN, &attr);
	if (retval != GKT_SUCCESS) {
		gkt_error("sliding_closure: wkio set failed %d\n", retval);
		return retval;
	}

	if (s_sliding_closure.detect
		&& (GKT_SYSTEM_RESET_WAKEUP == g_system_info.reset_mode)) 
	{
		wakedup = gkt_wkio_is_wakeup(GKT_CONFIG_SLIDING_CLOSURE_WKIO_PIN);
		if (wakedup)
			gkt_wakeup_set_source(GKT_WAKEUP_SRC_sliding_closure);
	}

	return GKT_SUCCESS;
}

#endif

